/* 
Copyright (c) 2004,2005, 2006, 2007, 2008 University of Illinois 

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
Mozilla Accessibility Extension
listofdatatables.js
JavaScript code for the list of data tables XUL component
*/
AccessibilityExtension.ns(function() { with (AccessibilityExtension.LIB) {

	var AE = AccessibilityExtension.ns;  
	AE.dialogName = "accessext-form-list-datatables";
	
	const tablemode_captionth_only = 1;
	const tablemode_headers_id	= 2;
	
	/*
	In the absence of header information from the headers attribute,
	user agents may construct header information according to the following algorithm.
	The goal of the algorithm is to find an ordered list of headers. (In the following
	description of the algorithm the table directionality is assumed to be left-to-right.)
	
	    * First, search left from the cell's position to find row header cells. Then
			search upwards to find column header cells. The search in a given direction
			stops when the edge of the table is reached or when a data cell is found
			after a header cell.
	
	    * Row headers are inserted into the list in the order they appear in the table.
			For left-to-right tables, headers are inserted from left to right.
	
	    * Column headers are inserted after row headers, in the order they appear in
			the table, from top to bottom.
	
	    * If a header cell has the headers attribute set, then the headers referenced
			by this attribute are inserted into the list and the search stops for the
			current direction.
	
	    * TD cells that set the axis attribute are also treated as header cells.
	*/
	
	var activeTable = null;
AccessibilityExtension.LIB.extend(AccessibilityExtension.LIB,
{	
	/******************* PARSING FUNCTIONS **********************/
	ParseDocument: function(doc) {
		ParseDocumentForDataTables(doc, AE.dataarray);
	},
	
	ParseDocumentForDataTables: function(node, loadArray) {
		//@todo: : Redo w/ xpath or at least getElementsByTagName 
		if (node.tagName && node.tagName.toLowerCase() == 'table') {
			if (accessext_isDataTable(node))
				loadArray[loadArray.length] = newDataTable(node,loadArray.length+1);
		}
	
		if(node.childNodes) {
			for(var i = 0; i < node.childNodes.length; i ++)
				ParseDocumentForDataTables(node.childNodes[i], loadArray);
		}
		for (var i=0, j=0, n=loadArray.length; i<n; i++) {    
			for (j=i+1; j<n; j++) {  
				if (loadArray[i].summary.toLowerCase() == loadArray[j].summary.toLowerCase()) { loadArray[i].duplicatesummary=loadArray[j].duplicatesummary=true;}	
			}
		}	
		
	},
	
	/***************************** DIALOG BOX FUNCTIONS ***********************/
	accessext_handle_treebox: function() {
		if(!AE.treebox)
			return;
	
		if(AE.treebox.currentIndex < 0 || AE.treebox.currentIndex >= AE.dataarray.length) {
			return;
		}
	
		var tbheaders = document.getElementById('tree-headers');
		if (!tbheaders)
			return;
	
		accessext_clearTreeItems(tbheaders);
		var findex = AE.treebox.currentIndex;
		
		activeTable = AE.dataarray[findex];
		activeTable.populateWindow(document);
		
		var node = activeTable.tableNode;
		if(node == null) {
			alert(accessext_getBundleString('varisnull',"activeTable.tableNode"));
			return;
		}
	
		//Enable buttons
		var b = document.getElementById("button-up");
		if (b) {
			b.disabled = false;
		}
		b = document.getElementById("button-down");
		if (b) {
			b.disabled = false;
		}
		b = document.getElementById("button-left");
		if (b) {
			b.disabled = false;
		}
		b = document.getElementById("button-right");
		if (b) {
			b.disabled = false;
		}
		
		node = activeTable.getActiveCell();
		if (node != null) {
			scrollAndHighlightActiveNode();		
		} else {
			alert(accessext_getBundleString('varisnull',"node"));
		}
		accessext_setNoteText(findex);
	
	},
	
	createHeaderElement: function(i,type,node) {
		var item, child, row;
		row = document.createElement("treerow");
		
		child = document.createElement("treecell");
		child.setAttribute("label", i.toString());
		row.appendChild(child);
		
		child = document.createElement("treecell");
		child.setAttribute("label", type);
		row.appendChild(child);
		
		var text = cleanSpaces(node.textContent);
		if (text == '') {text = accessext_getBundleSingleString('none');}
			
		child = document.createElement("treecell");
		child.setAttribute("label", text);
		row.appendChild(child);
		
		item = document.createElement("treeitem");
		item.setAttribute("value",i.toString());
		item.appendChild(row);
		return item;
	},
	
	populateHeaders: function() {
		if (activeTable == null) {
			return;
		}
	
		var tbheaders = document.getElementById('tree-headers');
		if (!tbheaders) {
			return;
		}
	
		var treeChildren = accessext_clearTreeItems(tbheaders);
		
	//SMF	accessext_clearHighlightedNodes();
		for (var i = 0; i < AE.highlightedNodes.length; i ++) {	accessext_styleNode(AE.highlightedNodes[i],false,false);}
	
		var styles = new Object();
		styles['backgroundColor'] = 'red';
		styles['color'] = 'white';
		
		var headers = activeTable.getHeadersForCoord(activeTable.activePos[0],activeTable.activePos[1]);
	
		var type = null;
		var item;
		var offset = 0;
		try {
			var ps = getAccessextPrefService();
	//		if ( ps.prefHasUserValue("datatables.toggle.enableRowAndColHeaders")
	//			&& ps.getBoolPref("datatables.toggle.enableRowAndColHeaders")) {
			if (headers.idHeaders.length <= 0) {
				type = accessext_getBundleSingleString('dataTables.type.row');
				for(var i = 0; i < headers.rowHeaders.length; i ++) {
					item = createHeaderElement(i,type,headers.rowHeaders[i]);
					treeChildren.appendChild(item);
					//highlightedNodes[highlightedNodes.length]=accessext_styleNode(headers.rowHeaders[i],styles,true);
				}
				offset += headers.rowHeaders.length;
				
				type = accessext_getBundleSingleString('dataTables.type.col');
				
				styles['backgroundColor']='blue';
				for(i = 0; i <  + headers.colHeaders.length; i ++) {
					item = createHeaderElement(offset + i,type,headers.colHeaders[i]);
					treeChildren.appendChild(item);
					//highlightedNodes[highlightedNodes.length]=accessext_styleNode(headers.colHeaders[i],styles,true);
				}
				
				offset += headers.colHeaders.length;
			}
		} catch (ex) {
			accessext_consoleDump('' + ex);
		}
		
		type = accessext_getBundleSingleString('dataTables.type.id');
		//var tablehelpHighlightNode,style, strColor, htmlNode;
		var r = new Object();
		htmlNode = AE.mydoc.defaultView.document.getElementsByTagName("html");
		
		for(i = 0; i < headers.idHeaders.length; i ++) {
			item = createHeaderElement(offset + i,type,headers.idHeaders[i]);
			treeChildren.appendChild(item);
		} 
	},
	
	setTableHelpHighlighting: function(){
		var headers = activeTable.getHeadersForCoord(activeTable.activePos[0],activeTable.activePos[1]);
		var tablehelpHighlightNode,style, strColor, htmlNode;
		var helpnodecounter = 0;
		var r = new Object();
		htmlNode = AE.mydoc.defaultView.document.getElementsByTagName("html");
		
		for(i = 0; i < headers.idHeaders.length; i ++) {
			tablehelpHighlightNode = AE.mydoc.defaultView.document.createElement('div');
			tablehelpHighlightNode.setAttribute('id', 'accessext-highlight-div-tablehelp-' + helpnodecounter);
			tablehelpHighlightNode.setAttribute('class', 'accessext-highlight-div-tablehelp-' + helpnodecounter);
			
			htmlNode[0].appendChild(tablehelpHighlightNode);
	
			r = accessext_getNodeDocPosition(headers.idHeaders[i]);
			style = 'position:absolute;top:' + r.y + 'px;left:' + r.x + 'px;width:' + r.width + 'px;height:' + r.height + 'px;';
			//strColor = EnsureHighlightColorVisibility(headers.idHeaders[i]);
			//style = style + ';background-color:' + strColor + ';border: ' + highlightBorder + ';border-style: dashed;opacity:0.5;visibility:show;font-style:bold';	
			//style = style + ';background-color:' + 'green' + ';opacity:0.5;visibility:show';	
			style = style + ';background-color:' + 'green' + ';opacity:0.5';	
			tablehelpHighlightNode.setAttribute('style', style);
			helpnodecounter++;	
		}
		if (headers.idHeaders.length <= 0) {
			for(var i = 0; i < headers.rowHeaders.length; i ++) {
				tablehelpHighlightNode = AE.mydoc.defaultView.document.createElement('div');
				tablehelpHighlightNode.setAttribute('id', 'accessext-highlight-div-tablehelp-' + helpnodecounter);
				tablehelpHighlightNode.setAttribute('class', 'accessext-highlight-div-tablehelp-' + helpnodecounter);
				
				htmlNode[0].appendChild(tablehelpHighlightNode);
		
				r = accessext_getNodeDocPosition(headers.rowHeaders[i]);
				style = 'position:absolute;top:' + r.y + 'px;left:' + r.x + 'px;width:' + r.width + 'px;height:' + r.height + 'px;';
				style = style + ';background-color:' + 'green' + ';opacity:0.5';	
				tablehelpHighlightNode.setAttribute('style', style);	
				helpnodecounter++;	
			}
			for(i = 0; i <  + headers.colHeaders.length; i ++) {
				tablehelpHighlightNode = AE.mydoc.defaultView.document.createElement('div');
				tablehelpHighlightNode.setAttribute('id', 'accessext-highlight-div-tablehelp-' + helpnodecounter);
				tablehelpHighlightNode.setAttribute('class', 'accessext-highlight-div-tablehelp-' + helpnodecounter);
				
				htmlNode[0].appendChild(tablehelpHighlightNode);
		
				r = accessext_getNodeDocPosition(headers.colHeaders[i]);
				style = 'position:absolute;top:' + r.y + 'px;left:' + r.x + 'px;width:' + r.width + 'px;height:' + r.height + 'px;';
				style = style + ';background-color:' + 'green' + ';opacity:0.5';	
				tablehelpHighlightNode.setAttribute('style', style);	
				helpnodecounter++;	
			}
		}
	},
	
	scrollAndHighlightActiveNode: function() {
		var node = activeTable.getActiveCell();
		if (node) {
			populateHeaders();
			accessext_scrollToNodeCentered(node);
			accessext_clearHighlightedNodes();
			//@todo: when there tables in in different FRAMES this will not work, needs to be fixed. Highlight node needs to be attached to table within (same) frame.
			accessext_highlightNode(node);	
			setTableHelpHighlighting();
				
			var prop;
			if (node.tagName.toLowerCase() == 'td') {
				prop = 'dataTables.cellType.td';
			} else {
				prop = 'dataTables.cellType.th';
			}
			
			var typeElement = document.getElementById('textbox-cell-type');
			if (typeElement) {
				typeElement.value = accessext_getBundleSingleString(prop);
			}
		}
	},
	
	tableMove: function(dir) {
		if (activeTable) {
			activeTable.moveActiveCell(dir);
			scrollAndHighlightActiveNode();
		}
	},
	
	UpdateTreeView: function() {
		var sc = document.getElementById(AE.sortColumn);
		if (sc == null) {
			accessext_consoleDump("Could not find column: " + AE.sortColumn);
			return;
		}
		var i;
	//Clear the children and create a new one
		var treeChildren = accessext_clearTreeItems(AE.treebox);
	
		//Sort
		//First clear all directions
		var cols = AE.treebox.getElementsByTagName("treecols");
		if (cols.length == 1) {
			for (i = 0; i < cols[0].childNodes.length; i ++)
				cols[0].childNodes[i].setAttribute("sortDirection","");
		}
	
		sc.setAttribute("sortDirection", AE.sortDirectionAscending ? "ascending" : "descending");
		switch (AE.sortColumn) {
			case 'list-header-main-title':
				AE.sortProperty="title";
			break;
			default:
				AE.sortProperty="order";
			break;
		}
		
		AE.dataarray.sort(accessext_sortColumnElements);
		
		//Finally add elements to the list
		for(i = 0; i < AE.dataarray.length; i ++) {
			var item = AE.dataarray[i].getTreeNode(document);
			item.setAttribute("value",i);
			treeChildren.appendChild(item);
		}
	},
	
	post_InitAccessibilityExt: function() {
		accessext_setNoteText(0);
	},
	
	CleanUp_DataTables: function() {
		CleanUp();
		accessext_clearHighlightedNodes();
	}
});
if (AccessibilityExtension.LIB.InitAccessibilityExt) AccessibilityExtension.LIB.InitAccessibilityExt();		
}});	